#include "game_logic.h"

#define MAX_LIFE 5000
#define MAX_FRUITS 16

#include "../gui/gui.h"
#include "../sfx/sfx.h"

void game_deathmatch_setup(Game *game)
{
    game->logic = game_deathmatch_logic;
    game->collide_entity =  game_deathmatch_collide_entity;
    game->collide_tilemap =  game_deathmatch_collide_tilemap;
    game->draw_player_gui = game_deathmatch_draw_player_gui;

    game->tilemap = gfx_tilemap_read("data/gfx/Map");

    if(game->tilemap == 0)
    {
        game->tilemap = gfx_tilemap_create("gfx_map_random", 20, 10);
       // gfx_tilemap_set_tiles(game->tilemap, 0, 0,    game->tilemap->width, 1, 1);
       // gfx_tilemap_set_tiles(game->tilemap, 0, game->tilemap->height-1,    game->tilemap->width, 1, 1);
       // gfx_tilemap_set_tiles(game->tilemap, 0, 0,                          1, game->tilemap->height, 1);
       // gfx_tilemap_set_tiles(game->tilemap, game->tilemap->width-1, 0,      1, game->tilemap->height, 1);
    }
    //gfx_tilemap_generate(game->tilemap);

    for(int i = 0; i < array_size(game->players); i++)
    {
        Game_Player *player = &game->players[i];
        Game_Entity *entity = &game->entities[player->entityIndex];
        entity->health=5000;
        entity->radius = 14;
        entity->entityType = ENTITY_PLAYER;
        player->superIndex = -1;
        player->superLevel = 1;
        player->superCharge = 1;
        player->superMaxCharge = 3;
        player->superChargeRechargeThink = 7.5;

        if(i == 0)
        {
            entity->sprite.image = gfx_image_get("game_player1");
            entity->x = 1.5*game->tilemap->image->width / game->tilemap->image->columns;
        }
        else if(i == 1)
        {
            entity->sprite.image = gfx_image_get("game_player2");
            entity->x = 38.5*game->tilemap->image->width / game->tilemap->image->columns;
        }

        entity->y = 15.5*game->tilemap->image->height / game->tilemap->image->rows;
        player->nbKeys = 0;
        entity->deleteFlag = 0;
    }

    // KEY SPAWN
int i;
    for(i=0; i < 3; i++)
    {
        Game_Entity *key = game_entity_spawn(game);
        key->radius = 8;
        key->entityType = ENTITY_KEY;
        key->sprite.image = gfx_image_get("game_keys");
        key->sprite.frame = 0;
        while(1)
        {
            int x =( rand() % game->tilemap->width)/2;
            int y = rand() % game->tilemap->height;
            if(gfx_tilemap_get_tile(game->tilemap, x, y)) continue;
            key->x = (x + 0.5) * game->tilemap->image->width / game->tilemap->image->columns;
            key->y = (y + 0.5) * game->tilemap->image->height / game->tilemap->image->rows;
            break;
        }
    }
    for(i=0; i < 3; i++)
    {
        Game_Entity *key = game_entity_spawn(game);
        key->radius = 8;
        key->entityType = ENTITY_KEY;
        key->sprite.image = gfx_image_get("game_keys");
        key->sprite.frame = 1;
        while(1)
        {
            int x =( rand() % game->tilemap->width)/2 + game->tilemap->width/2;
            int y = rand() % game->tilemap->height;
            if(gfx_tilemap_get_tile(game->tilemap, x, y)) continue;
            key->x = (x + 0.5) * game->tilemap->image->width / game->tilemap->image->columns;
            key->y = (y + 0.5) * game->tilemap->image->height / game->tilemap->image->rows;
            break;
        }
    }
}

int game_deathmatch_logic(void *game, float ticks)
{
    Game *server = game;

    // Check game over status
    if(server->gameOver)
    {
        for(int i = 0; i < array_size(server->players); i++)
        {
            Game_Player *player = &server->players[i];
            if(player->inUse)
            {
                Game_Entity *entity = &server->entities[player->entityIndex];
                entity->dx = 0;
                entity->dy = 0;
                if(player->superIndex)
                {
                    Game_Entity *super = &server->entities[player->superIndex];
                    super->dx = 0;
                    super->dy = 0;
                }
            }
        }

        if(clock_get(server->time) > server->gameOverTimeout) return -1;
        return 0;
    }

    int nbPlayersAlive = 0;
    // Player-specific logic
    for(int i = 0; i < array_size(server->players); i++)
    {
        Game_Player *player = &server->players[i];
        if(player->inUse)
        {
            game_deathmatch_input_player(server, player, ticks);
            Game_Entity *entity = &server->entities[player->entityIndex];

            // Supercharge recharge
            if(player->superCharge < player->superMaxCharge)
            {
                player->superChargeRechargeThink -= ticks;
                if(player->superChargeRechargeThink < 0)
                {
                    if(player->superCharge < player->superMaxCharge)
                    {
                        player->superCharge++;
                        player->superChargeRechargeThink = 7.5;
                    }
                }
            }

            if(player->superIndex < 0)
            {
                player->camX = entity->x;
                player->camY = entity->y;
            }
            else
            {
                Game_Entity *super = &server->entities[player->superIndex];
                player->camX = super->x;
                player->camY = super->y;
            }

            entity->health-=100*ticks;

            if(entity->health <= 0)
            {
                player->winStatus = -1;
                entity->health = 0;
            }
            else
            {
                player->winStatus = 0;
                nbPlayersAlive++;
            }

            if(entity->health > MAX_LIFE)
            {
                entity->health = MAX_LIFE;
            }
        }
    }

    // Check win conditions
    if(nbPlayersAlive <= 1)
    {
        //sfx_play(0, SFX_SOUND_RIRE);
        server->gameOver = 1;
        server->gameOverTimeout = clock_get(server->time) + 5;
        for(int i = 0; i < array_size(server->players); i++)
        {
            Game_Player *player = &server->players[i];
            if(player->inUse)
            {
                Game_Entity *entity = &server->entities[player->entityIndex];

                if(entity->health > 0)
                {
                    player->winStatus = 1;
                }
            }
        }
    }

    // Spawn fruits
    int nbFruits = 0;
    for(int i = 0; i < array_size(server->entities); i++)
    {
        Game_Entity *e = &server->entities[i];
        if(e->inUse && e->entityType == ENTITY_FOOD)
        {
            nbFruits++;
        }
    }
    for(; nbFruits < MAX_FRUITS/((clock_get(server->time)/120 + 1)); nbFruits++)
    {
        Game_Entity *fruit = game_entity_spawn(game);
        fruit->radius = 8;
        fruit->entityType = ENTITY_FOOD;
        fruit->sprite.image = gfx_image_get("game_fruits");
        fruit->sprite.frame = rand() % 30;
        while(1)
        {
            int x = rand() % server->tilemap->width;
            int y = rand() % server->tilemap->height;
            if(gfx_tilemap_get_tile(server->tilemap, x, y)) continue;
            fruit->x = (x + 0.5) * server->tilemap->image->width / server->tilemap->image->columns;
            fruit->y = (y + 0.5) * server->tilemap->image->height / server->tilemap->image->rows;
            break;
        }
    }

    //open door
    for(int i = 0; i < array_size(server->players); i++)
    {
        Game_Player *player = &server->players[i];
        if(player->inUse)
        {
            Game_Entity *entity = &server->entities[player->entityIndex];

            if(player->nbKeys == 6 )
            {
                if(entity->player==0)
                {
                    gfx_tilemap_set_tile(server->tilemap,19,1,0);
                    player->superMaxCharge = 6;
                }
                else if(entity->player==1)
                {
                    gfx_tilemap_set_tile(server->tilemap,20,1,0);
                    player->superMaxCharge = 6;
                }
            }

        }
    }
    return 0;
}

void game_deathmatch_collide_entity(void *game, float ticks, Game_Entity *e1, Game_Entity *e2)
{
    Game *server = game;
    if(e1->entityType == ENTITY_PLAYER)
    {
        if(e2->entityType == ENTITY_FOOD)
        {
            sfx_play(0, SFX_MENU_ENTER);
            e1->health+=300;
            e2->deleteFlag = 1;
            return;
        }
        else if (e2->entityType == ENTITY_FOOD_EMPOI)
        {
            sfx_play(0, SFX_SOUND_JESUISMALADE);
            e1->health-=600;

            Game_Player *other = &server->players[1-e1->player];
            Game_Entity *eother = &server->entities[other->entityIndex];
            eother->health += 600/3;

            e2->deleteFlag = 1;
            return;
        }
        else if (e2->entityType == ENTITY_KEY)
        {
            Game_Player *player = &server->players[e1->player];
            player->nbKeys++;
            e2->deleteFlag = 1;
            return;
        }

    }
    if(e1->entityType == ENTITY_SUPER)
    {
        if(e2->entityType == ENTITY_FOOD)
        {
            Game_Player *player = &server->players[e1->player];
            if(player->actions & PLAYER_B && player->superCharge > 0)
            {
                e2->entityType = ENTITY_FOOD_EMPOI;
                player->superCharge--;
            }
            return;
        }
        return;
    }
    if(e2->entityType == ENTITY_SUPER) return;

    // Default action is to push entities
    game_collide_reponse_entity_entity(game, ticks, e1, e2);
}

void game_deathmatch_collide_tilemap(void *game, float ticks, Game_Entity *e, int xtile, int ytile)
{
    Game *server = game;
    if(e->entityType == ENTITY_SUPER)
    {
        return;
    }

    int tile = gfx_tilemap_get_tile(server->tilemap, xtile, ytile);
    if(tile)
    {
        game_collide_reponse_entity_tilemap(game, ticks, e, xtile, ytile);
    }
}

void game_deathmatch_draw_player_gui(void *game, int w, int h, int localPlayer)
{
    Game *server = game;

    Game_Player *player = &server->players[localPlayer];
    Game_Entity *entity = &server->entities[player->entityIndex];

    // Draw healthbar
    #define _HEALTHBAR_SIZE 20
    GFX_Tilemap *health = gfx_tilemap_create("game_lifebar", _HEALTHBAR_SIZE, 1);
    health->x = 16;
    health->y = 16;
    for(int i = 0; i < _HEALTHBAR_SIZE; i++)
    {
        int active;
        if(entity->health > ((float)(i) / (_HEALTHBAR_SIZE) * MAX_LIFE))
        {
            active = 1;
        }
        else
        {
            active = 0;
        }

        int tile;
        if(i == 0) tile = active * 3;
        else if(i == _HEALTHBAR_SIZE-1) tile = 2+3*active;
        else tile = 1+(active*3);

        gfx_tilemap_set_tile(health, i, 0, tile);
    }
    gfx_render_tilemap(health);
    gfx_tilemap_delete(health);

    // Draw superbar
    GFX_Tilemap *bar = gfx_tilemap_create("game_superbar", player->superMaxCharge, 1);
    bar->x = 16;
    bar->y = 16*3;
    for(int i = 0; i < player->superMaxCharge; i++)
    {
        int active;
        if(player->superCharge > i)
        {
            active = 1;
        }
        else
        {
            active = 0;
        }

        int tile;
        if(i == 0) tile = active * 3;
        else if(i == player->superMaxCharge-1) tile = 2+3*active;
        else tile = 1+(active*3);

        gfx_tilemap_set_tile(bar, i, 0, tile);
    }
    gfx_render_tilemap(bar);
    gfx_tilemap_delete(bar);

    // Draw win/lost message
    GFX_String *message = 0;
    if(player->winStatus > 0)
    {
        message = gfx_string_create("gfx_font", "You win");
    }
    else if(player->winStatus < 0)
    {
        message = gfx_string_create("gfx_font", "You lose");
    }
    if(message)
    {
        message->x = w/2 - strlen(message->text) * 4;
        message->y = h/2 - 8;
        gfx_render_string(message);
        gfx_string_delete(message);
    }
    else if(player->inPause)
    {
        int status = gui_menu_pause(&player->itemPause, h);
        if(status == 1)
        {
            player->inPause = 0;
            clock_start(server->time);
        }
        else if(status == 2)
        {
            clock_start(server->time);
            server->gameOver = 1;
            server->gameOverTimeout = -1e10;
        }
    }
}

void game_deathmatch_input_player(Game *server, Game_Player *player, float ticks)
{
    if(player->inUse)
    {
        Game_Entity *entity = &server->entities[player->entityIndex];
        entity->dx = 0;
        entity->dy = 0;
        if(entity->health == 0)
        {
            return;
        }

        // Player/supernatural secetion
        if(player->actions & PLAYER_A)
        {
            if(player->superIndex < 0)
            {
                Game_Entity *super = game_entity_spawn(server);
                super->entityType = ENTITY_SUPER;
                super->x = entity->x;
                super->y = entity->y;
                super->radius = 16;
                super->player = player->playerIndex;
                super->sprite.image = gfx_image_get("game_player1super");
                player->superIndex = super->entityIndex;
            }
        }
        else
        {
            if(player->superIndex > 0)
            {
                Game_Entity *super = &server->entities[player->superIndex];
                super->deleteFlag = 1;
                super->player = player->playerIndex;
                player->superIndex = -1;
            }
        }

        // Player moving
        if(player->superIndex < 0)
        {
            if(player->actions & PLAYER_UP)
            {
                entity->dy = -64*1.5;
                entity->baseAnim = 0;
            }
            if(player->actions & PLAYER_DOWN)
            {
                entity->dy = +64*1.5;
                entity->baseAnim = 18;
            }
            if(player->actions & PLAYER_LEFT)
            {
                entity->dx = -64*1.5;
                entity->baseAnim = 9;
            }
            if(player->actions & PLAYER_RIGHT)
            {
                entity->dx = +64*1.5;
                entity->baseAnim = 27;
            }

            // Player animation
            if(entity->dx == 0 && entity->dy == 0)
            {
                entity->animTime = 0;
                entity->sprite.frame = entity->baseAnim;
            }
            else
            {
                entity->animTime += ticks;
                entity->sprite.frame = ((int)(entity->animTime * 10) % 8) + entity->baseAnim + 1;
            }
        }
        // Supernatural moving
        else
        {
            Game_Entity *e = &server->entities[player->superIndex];
            e->dx = e->dy = 0;
            if(player->actions & PLAYER_UP)
            {
                e->dy = -64*4;
                e->baseAnim = 0;
            }
            if(player->actions & PLAYER_DOWN)
            {
                e->dy = +64*4;
                e->baseAnim = 6;
            }
            if(player->actions & PLAYER_LEFT)
            {
                e->dx = -64*4;
                e->baseAnim = 3;
            }
            if(player->actions & PLAYER_RIGHT)
            {
                e->dx = +64*4;
                e->baseAnim = 9;
            }

            // Supernatural animation
            e->animTime += ticks;
            e->sprite.frame = ((int)(e->animTime * 15) % 3) + e->baseAnim;
        }

        if(player->actions & PLAYER_START)
        {
            if(!server->time->isPaused)
            {
                player->inPause = 1;
                player->itemPause = 0;
                clock_pause(server->time);
            }
        }
    }
}
